import logging
from flask import Flask, request, jsonify
import pandas as pd
import os
from datetime import datetime
from reportlab.lib.pagesizes import letter
from reportlab.platypus import (
    SimpleDocTemplate,
    Table,
    TableStyle,
    Paragraph,
    Spacer,
    Image,
)
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib import colors
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont


app = Flask(__name__)
logging.basicConfig(level=logging.DEBUG)

# 确保data目录存在
DATA_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")
if not os.path.exists(DATA_DIR):
    os.makedirs(DATA_DIR)

# 确保logos目录存在
LOGOS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), "logos")
if not os.path.exists(LOGOS_DIR):
    os.makedirs(LOGOS_DIR)


@app.route("/create_excel", methods=["POST"])
def create_excel():
    app.logger.debug("Received POST request to /create_excel")
    try:
        # 获取请求中的数据
        data = request.json
        fields = data.get("fields", [])
        values = data.get("values", {})

        # 输入验证
        if not fields or not isinstance(fields, list) or len(fields) == 0:
            err = {"error": "'fields' must be a non-empty list."}
            return jsonify(err), 400

        if not values or not isinstance(values, dict):
            return jsonify({"error": "'values' must be a dictionary."}), 400

        # 检查所有值列表是否长度一致
        expected_length = None
        for field in fields:
            if field not in values:
                err = {"error": f"Missing values for field '{field}'."}
                return jsonify(err), 400

            current_length = len(values[field])
            if expected_length is None:
                expected_length = current_length
            elif current_length != expected_length:
                err = {
                    "error": (
                        "All value lists must have the same length. "
                        f"Field '{field}' does not match."
                    )
                }
                return jsonify(err), 400

        app.logger.debug(f"Fields received: {fields}")
        app.logger.debug(f"Values received: {values}")

        # 创建带有数据的DataFrame
        df_data = {
            field: values.get(field, [None] * expected_length)
            for field in fields
        }
        df = pd.DataFrame(df_data)

        # 定义文件名和完整路径，确保文件名唯一
        base_filename = "output_{}.xlsx"
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[
            :-3
        ]  # 使用毫秒级时间戳确保唯一性
        filename = base_filename.format(timestamp)
        file_path = os.path.join(DATA_DIR, filename)

        # 检查文件是否存在，如果存在则添加序号以保证文件名唯一
        counter = 1
        while os.path.exists(file_path):
            filename = base_filename.format(f"{timestamp}_{counter}")
            file_path = os.path.join(DATA_DIR, filename)
            counter += 1

        # 保存到Excel文件
        with pd.ExcelWriter(file_path, engine="xlsxwriter") as writer:
            df.to_excel(writer, index=False)

        app.logger.debug(f"Excel file saved to: {file_path}")

        # 返回文件路径作为响应
        resp = {
            "message": "File created successfully.",
            "file_path": file_path,
        }
        return jsonify(resp), 200

    except Exception as e:
        app.logger.error(f"An error occurred: {str(e)}")
        return jsonify({"error": str(e)}), 500


@app.route("/create_pdf", methods=["POST"])
def create_pdf():
    app.logger.debug("Received POST request to /create_pdf")
    try:
        # 获取请求中的数据
        data = request.json
        fields = data.get("fields", [])
        values = data.get("values", {})

        # 输入验证
        if not fields or not isinstance(fields, list) or len(fields) == 0:
            err = {"error": '"fields" must be a non-empty list.'}
            return jsonify(err), 400

        if not values or not isinstance(values, dict):
            return jsonify({"error": '"values" must be a dictionary.'}), 400

        # 检查所有值列表是否长度一致
        expected_length = None
        for field in fields:
            if field not in values:
                err = {"error": f'Missing values for field "{field}".'}
                return jsonify(err), 400

            current_length = len(values[field])
            if expected_length is None:
                expected_length = current_length
            elif current_length != expected_length:
                err = {
                    "error": (
                        "All value lists must have the same length. "
                        f'Field "{field}" does not match.'
                    )
                }
                return jsonify(err), 400

        app.logger.debug(f"Fields received: {fields}")
        app.logger.debug(f"Values received: {values}")

        # 创建带有数据的DataFrame
        df_data = {
            field: values.get(field, [None] * expected_length)
            for field in fields
        }
        df = pd.DataFrame(df_data)

        # 定义文件名和完整路径，确保文件名唯一
        base_filename = "output_{}.pdf"
        timestamp = datetime.now().strftime("%Y%m%d_%H%M%S_%f")[
            :-3
        ]  # 使用毫秒级时间戳确保唯一性
        filename = base_filename.format(timestamp)
        file_path = os.path.join(DATA_DIR, filename)

        # 检查文件是否存在，如果存在则添加序号以保证文件名唯一
        counter = 1
        while os.path.exists(file_path):
            filename = base_filename.format(f"{timestamp}_{counter}")
            file_path = os.path.join(DATA_DIR, filename)
            counter += 1

        # 注册中文字体支持
        chinese_font_name = "DefaultFont"  # 默认字体名称
        try:
            # Windows系统常见的中文字体路径
            chinese_fonts = [
                ("C:/Windows/Fonts/msyh.ttc", "MicrosoftYaHei"),  # 微软雅黑
                ("C:/Windows/Fonts/simhei.ttf", "SimHei"),  # 黑体
                ("C:/Windows/Fonts/simsun.ttc", "SimSun"),  # 宋体
            ]

            for font_path, font_name in chinese_fonts:
                if os.path.exists(font_path):
                    pdfmetrics.registerFont(TTFont(font_name, font_path))
                    chinese_font_name = font_name
                    app.logger.debug(
                        f"Successfully registered Chinese font: {font_name}"
                    )
                    break
        except Exception as e:
            app.logger.warning(f"Failed to register Chinese fonts: {str(e)}")
            # 如果无法注册字体，使用默认字体
            chinese_font_name = "Helvetica"

        # 创建PDF文件
        doc = SimpleDocTemplate(file_path, pagesize=letter)
        elements = []

        # 尝试添加logo图片（高度固定为50，保持原始宽高比）
        logo_path = os.path.join(LOGOS_DIR, "logo.png")
        if os.path.exists(logo_path):
            try:
                # 目标高度（单位：points）
                target_height = 30
                # 如果安装了 Pillow，则使用它读取原始尺寸并计算等比宽度
                try:
                    from PIL import Image as PILImage

                    with PILImage.open(logo_path) as pil_img:
                        orig_w, orig_h = pil_img.size
                        if orig_h > 0:
                            ratio = float(target_height) / float(orig_h)
                            target_width = float(orig_w) * ratio
                        else:
                            target_width = None
                except Exception:
                    # Pillow 不可用或出错时，让 ReportLab 只设置 height，由其自行保持比例
                    target_width = None

                if target_width:
                    logo = Image(
                        logo_path,
                        width=target_width,
                        height=target_height,
                    )
                else:
                    # 只传入 height，ReportLab 会按比例缩放（当只指定一个边时通常保持比例）
                    logo = Image(logo_path, height=target_height)

                # 在图片右侧添加文字：为简化航运而生。 字号为10，且垂直居中对齐
                caption_style = ParagraphStyle(
                    "LogoCaption",
                    parent=getSampleStyleSheet()["Normal"],
                    fontName=chinese_font_name,
                    fontSize=10,
                    leading=12,
                )
                caption = Paragraph("为简化航运而生", caption_style)

                # 使用一个一行两列的 Table 将图片和文字横向放置，并使其垂直居中
                # 如果我们已计算出 target_width，则将其作为第一列宽度，否则让 ReportLab 自行计算
                col_widths = [target_width if target_width else None, None]
                logo_row = Table([[logo, caption]], colWidths=col_widths)
                logo_row.setStyle(
                    TableStyle(
                        [
                            ("VALIGN", (0, 0), (-1, -1), "BOTTOM"),
                            # image cell padding: no left padding,
                            # a bit of right padding
                            ("LEFTPADDING", (0, 0), (0, 0), 0),
                            ("RIGHTPADDING", (0, 0), (0, 0), 8),
                            # caption cell: add left padding to
                            # create space from image
                            ("LEFTPADDING", (1, 0), (1, 0), 12),
                            ("RIGHTPADDING", (1, 0), (1, 0), 0),
                        ]
                    )
                )

                elements.append(logo_row)
                elements.append(Spacer(1, 12))
                app.logger.debug(f"Logo and caption added to PDF: {logo_path}")
            except Exception as e:
                app.logger.warning(f"Failed to add logo: {str(e)}")
        else:
            app.logger.debug(f"Logo file not found: {logo_path}")

        # 创建支持中文的样式
        title_style = ParagraphStyle(
            "CustomTitle",
            parent=getSampleStyleSheet()["Title"],
            fontName=chinese_font_name,
            fontSize=18,
            spaceAfter=30,
        )

        # 添加标题
        title = Paragraph("数据报告", title_style)
        elements.append(title)
        elements.append(Spacer(1, 12))

        # 创建表格数据
        table_data = [fields]  # 表头
        for i in range(expected_length):
            row = [df.iloc[i][field] for field in fields]
            table_data.append(row)

        # 创建表格
        table = Table(table_data)
        table.setStyle(
            TableStyle(
                [
                    ("BACKGROUND", (0, 0), (-1, 0), colors.grey),
                    ("TEXTCOLOR", (0, 0), (-1, 0), colors.whitesmoke),
                    ("ALIGN", (0, 0), (-1, -1), "CENTER"),
                    (
                        "FONTNAME",
                        (0, 0),
                        (-1, 0),
                        chinese_font_name,
                    ),  # 表头使用中文字体
                    ("FONTSIZE", (0, 0), (-1, 0), 12),
                    ("BOTTOMPADDING", (0, 0), (-1, 0), 12),
                    ("BACKGROUND", (0, 1), (-1, -1), colors.beige),
                    (
                        "FONTNAME",
                        (0, 1),
                        (-1, -1),
                        chinese_font_name,
                    ),  # 表格内容使用中文字体
                    ("FONTSIZE", (0, 1), (-1, -1), 10),
                    ("GRID", (0, 0), (-1, -1), 1, colors.black),
                ]
            )
        )

        elements.append(table)

        # 将免责声明移至每页底部 footer（居中，距底部保留一定间距）
        disclaimer_text = (
            "报价报纯属虚构，如有雷同，概不负责！如你相信，概不负责。"
        )

        def draw_footer(canvas, doc_obj):
            """Draw disclaimer centered above bottom margin on each page."""
            canvas.saveState()
            page_width, page_height = doc_obj.pagesize

            # Footer style (reuse registered Chinese font if available)
            footer_style = ParagraphStyle(
                "Footer",
                parent=getSampleStyleSheet()["Normal"],
                fontName=chinese_font_name,
                fontSize=9,
                leading=11,
                alignment=1,  # center
                textColor=colors.grey,
            )

            p = Paragraph(disclaimer_text, footer_style)

            # wrap the paragraph to the page width minus side margins
            available_width = (
                page_width - doc_obj.leftMargin - doc_obj.rightMargin
            )
            w, h = p.wrap(available_width, doc_obj.bottomMargin)

            # place it centered, a bit above the bottom (leave aesthetic gap)
            x = doc_obj.leftMargin + (available_width - w) / 2.0
            # slightly below content area; positive keeps it above edge
            y = doc_obj.bottomMargin - 6
            if y < 24:
                # ensure there's a minimum distance from the page edge
                y = 24

            # draw the paragraph
            p.drawOn(canvas, x, y)
            canvas.restoreState()

        # build with footer callbacks so the disclaimer appears on every page
        doc.build(elements, onFirstPage=draw_footer, onLaterPages=draw_footer)

        app.logger.debug(f"PDF file saved to: {file_path}")

        # 返回文件路径作为响应
        resp = {
            "message": "PDF file created successfully.",
            "file_path": file_path,
        }
        return jsonify(resp), 200

    except Exception as e:
        app.logger.error(f"An error occurred: {str(e)}")
        return jsonify({"error": str(e)}), 500


if __name__ == "__main__":
    app.run(host="0.0.0.0", port=9000, debug=True)
